package jee.boot.module.bpm.delegated;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import jee.boot.common.utils.JsonMapper;
import jee.boot.common.utils.StringUtils;
import jee.boot.common.utils.excel.service.DictionaryTranslateHelper;
import jee.boot.entity.bpm.*;
import jee.boot.entity.bpm.BpmConstant;
import jee.boot.entity.task.ExcelUtils;
import jee.boot.module.bpm.dao.BusinessDataDao;
import jee.boot.module.bpm.service.FormDefinitionService;
import jee.boot.entity.task.IexpTaskConfig;
import jee.boot.entity.task.IexpTask;
import jee.boot.entity.task.ImportExecuteService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class BusinessDataImport extends BasicDelegated implements ImportExecuteService {
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private FormDefinitionService formDefinitionService;
    @Autowired
    private BusinessDataDao businessDataDao;
    /**
     * 关联表数据缓存
     */
    private ThreadLocal<Map<String, List<Map<String, Object>>>> joinDataMap = new ThreadLocal<Map<String, List<Map<String, Object>>>>() {
        @Override
        protected Map<String, List<Map<String, Object>>> initialValue() {
            return new HashMap<>();
        }
    };

    /**
     * 存储数据,可以存储到数据库或者其他地方,如果对导入的数据进行逻辑校验不通过时候,可以将校验结果保存到task.itemList中,然后抛出异常即可
     *
     * @param task 当前任务
     * @param data 任务数据对象如果是单sheet页的话，返回的是List，如果是多sheet页的话，返回的是一个Map对象，key是sheet页的名称
     */
    @Override
    public void storeData(IexpTask task, Object data) {
        // Excel上传上了的数据以map形式存储
        List<Map<String, Object>> dataList = (List<Map<String, Object>>) ((Map<String, Object>) data).get("0");
        String jsonParam = task.getJsonParam();
        BusinessData businessData = new BusinessData();
        if (StringUtils.isNotBlank(jsonParam)) {
            try {
                Map<String, Object> param = JsonMapper.fromJsonString(jsonParam, Map.class);
                businessData.setDefinition(new FormDefinition((String) param.get("definitionName")));
            } catch (Exception e) {
                logger.warn("解析参数失败,使用默认参数", e);
            }
        }
        FormDefinition definition = formDefinitionService.getCompleteDataByName(businessData.getDefinition());
        businessData.configDefinition(definition);
        FormConfig formConfig = definition.coverConfig();
        mixInBusinessColumn(formConfig, businessData);
        // 转换数据(A_1='123' -> name='123')
        List<Map<String, Object>> list = excelData2DbData(formConfig, dataList);
        // 混入关联数据
        mixInJoinData(businessData, list, formConfig);
        // 存储数据
        saveData(businessData, list);
    }

    /**
     * 主数据翻译
     *
     * @param businessData
     * @param list
     * @param formConfig
     */
    private void mixInJoinData(BusinessData businessData, List<Map<String, Object>> list, FormConfig formConfig) {
        cacheJoinData(businessData);
        resetPrimaryKey(list, formConfig);
        clear();
    }

    /**
     * 重载主键数据
     *
     * @param list
     * @param formConfig
     */
    private void resetPrimaryKey(List<Map<String, Object>> list, FormConfig formConfig) {
        if (list != null && !list.isEmpty()) {
            // 如果是map类型,则该属性为关联主数据属性,需要根据已上传的所有数据查找与主数据进行一一比对,比对成功后,则进行主数据覆盖
            list.stream().flatMap(data -> data.entrySet().stream()).filter(entry -> entry.getValue() instanceof Map).forEach(entry -> {
                String key = entry.getKey();
                Map<String, Object> mapData = (Map<String, Object>) entry.getValue();
                List<Map<String, Object>> joinDataList = this.joinDataMap.get().get(key);
                if (joinDataList != null && !joinDataList.isEmpty()) {
                    for (Map<String, Object> joinDataMap : joinDataList) {
                        // 如果根据已上传的数据match上系统内的数据,则进行数据覆盖
                        if (match(mapData, joinDataMap)) {
                            mapData.putAll(joinDataMap);
                        }
                    }
                }
            });
        }
    }

    /**
     * 匹配 mapData 中的所有数据,是否都在 joinDataMap 中
     *
     * @param mapData
     * @param joinDataMap
     * @return
     */
    private boolean match(Map<String, Object> mapData, Map<String, Object> joinDataMap) {
        if (mapData != null && joinDataMap != null) {
            boolean matchAll = true;// 匹配所有
            boolean matchOnce = false; // 匹配一次
            for (Map.Entry<String, Object> entry : mapData.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                Object o = joinDataMap.get(key);
                if (value != null && StringUtils.isNotBlank(value.toString())) {
                    if (!equals(value, o)) {
                        matchAll = false;
                        break;
                    } else {
                        matchOnce = true;
                    }
                }
            }
            return matchOnce && matchAll;
        }
        return false;
    }

    private boolean equals(Object value, Object o) {
        if (value == null || o == null) {
            return false;
        }
        return value.equals(o);
    }

    /**
     * 缓存数据
     *
     * @param businessData
     */
    private void cacheJoinData(BusinessData businessData) {
        // 下级子表关系
        List<BusTableRel> children = businessData.getRelChildren(businessData.getRelation(), BpmConstant.BPM_BUSINESS_TABLE_REL_TYPE_ONE_TO_ONE);
        if (children != null && !children.isEmpty()) {
            for (BusTableRel rel : children) {
                BusinessData one = new BusinessData();
                one.configDefinition(rel);
                // 加载所有数据
                List<Map<String, Object>> listData = businessDataDao.findList(one);
                joinDataMap.get().put(businessData.getJoinTableAlias(rel.getFks()), listData);
            }
        }
    }

    private void clear() {
        joinDataMap.get().clear();
    }

    /**
     * 存储数据
     *
     * @param businessData
     * @param list
     */
    private void saveData(BusinessData businessData, List<Map<String, Object>> list) {
        List<BusinessData> dataList = Lists.newArrayList();
        if (list != null && !list.isEmpty()) {
            for (Map<String, Object> map : list) {
                BusinessData data = new BusinessData();
                data.setData(map);
                data.configDefinition(businessData.getDefinition());
                dataList.add(data);
            }
            businessDataService.batchSave(dataList);
        }
    }


    private List<Map<String, Object>> excelData2DbData(FormConfig formConfig, List<Map<String, Object>> excelData) {
        DictionaryTranslateHelper dictionaryTranslateHelper = DictionaryTranslateHelper.getInstance();
        List<Map<String, Object>> retList = Lists.newArrayList();
        if (excelData != null && !excelData.isEmpty()) {
            List<ColumnConfig> columnList = formConfig.getColumnList().stream().filter(c -> StringUtils.equals(c.getImp(), BpmConstant.SYS_YES)).collect(Collectors.toList());
            // 默认从excel的第3行开始读数据
            int dataLine = 3;
            for (Map<String, Object> data : excelData) {
                Map<String, Object> map = Maps.newHashMap();
                int index = 0;
                for (ColumnConfig c : columnList) {
                    String s = ExcelUtils.toExcelName(index++);
                    Object o = data.get(s + "_" + dataLine);
                    // 字典类型,需要翻译下
                    if (o != null && StringUtils.isNotBlank(c.getColumn().getDictionaryType())) {
                        String dictLabel = dictionaryTranslateHelper.getDictLabel(o.toString(), c.getColumn().getDictionaryType());
                        o = dictLabel;
                    }
                    put(c.getFieldName(), o, map);
                }
                dataLine++;
                retList.add(map);
            }
        }
        dictionaryTranslateHelper.clear();
        return retList;
    }

    /**
     * 提供导入导出的配置,包括模板,名称等等
     *
     * @param task
     * @return
     */
    @Override
    public IexpTaskConfig taskConfig(IexpTask task) {
        IexpTaskConfig config = new IexpTaskConfig();
        return config;
    }

    /**
     * 将
     *
     * @param key
     * @param value
     * @param map
     */
    private void put(String key, Object value, Map<String, Object> map) {
        String[] split = StringUtils.split(key, ".");
        Iterator<String> iterator = Lists.newArrayList(split).iterator();

        Map<String, Object> tempMap = map;

        while (iterator.hasNext()) {
            String current = iterator.next();
            if (iterator.hasNext()) {
                // 如果还有下一个节点,找出或者新建一个子对象
                Map<String, Object> temp = (Map<String, Object>) tempMap.get(current);
                if (temp == null) {
                    temp = Maps.newHashMap();
                    tempMap.put(current, temp);
                }
                tempMap = temp;
            } else {
                //如果没有下一个节点,则放入到map中
                tempMap.put(current, value);
            }

        }
    }

    public static void main(String[] args) {

        Map<String, Object> map = Maps.newHashMap();
        BusinessDataImport dataImport = new BusinessDataImport();
        dataImport.put("user.company.name", "zhangsan", map);
        dataImport.put("user.company.code", "123456", map);
        dataImport.put("user.name", "888888", map);
        dataImport.put("user.code", "999999", map);
        dataImport.put("code", "1111", map);
        dataImport.put("name", "22222", map);
        dataImport.put("addr.name", "北京", map);
        dataImport.put("addr.code", "bj", map);
        System.out.println(map);
    }
}
